#include "CrissCross.h"

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

void CrissCross::drawCriss(IplImage* img, int i, int j, int radius, bool win)
{
       int x = img->width*(i+0.5)/n;
       int y = (img->height - textArea)*(j+0.5)/n; 
       if (!win){
                cvCircle(img,cvPoint(x, y),radius,CV_RGB(250,0,0),1,8);
        }else{
                cvCircle(img,cvPoint(x, y),radius,CV_RGB(0,250,0),1,8);
        }
}

void CrissCross::drawCross(IplImage* img, int i, int j, int radius, bool win)
{
       int x = img->width*(i+0.5)/n;
       int y = (img->height - textArea)*(j+0.5)/n; 
        if (!win){
                cvLine(img, cvPoint(x-radius/2, y-radius/2), cvPoint(x+radius/2, y+radius/2),CV_RGB(250,0,0),1,8);
                cvLine(img, cvPoint(x-radius/2, y+radius/2), cvPoint(x+radius/2, y-radius/2),CV_RGB(250,0,0),1,8);
        }else{
                cvLine(img, cvPoint(x-radius/2, y-radius/2), cvPoint(x+radius/2, y+radius/2),CV_RGB(0,250,0),1,8);
                cvLine(img, cvPoint(x-radius/2, y+radius/2), cvPoint(x+radius/2, y-radius/2),CV_RGB(0,250,0),1,8);
        }
}

void CrissCross::check (int player, int nx, int ny)
{
        int count;
        int startX   = ((nx - k + 1) > 0) ? (nx - k + 1) : 0;
        int endX     = ((nx + k - 1) < n) ? (nx + k - 1) : n;
        int startY   = ((ny - k + 1) > 0) ? (ny - k + 1) : 0;
        int endY     = ((ny + k - 1) < n) ? (nx + k - 1) : n;
	int deltaleft;
	int deltaright;

        //горизонталь
        count = 0;
        for (int i = startX; i < endX; ++i){
                if (arr[i][ny] == player){
                         ++count;
                         if (count == k){
                                 for (int j = 0; j < k; ++j){
                                        arr[i-j][ny] = player + 2;
                                }
                                ifFinished = true;
                                message = "game over";
                                return;
                        }
                }else{
                      count = 0;
                }
        }

        //вертикаль
        count = 0;
        for (int i = startY; i < endY; ++i){
                if (arr[nx][i] == player){
                        ++count;
                        if (count == k){
                                for (int j = 0; j < k; ++j){
                                        arr[nx][i-j] = player + 2;
                                }
                                ifFinished = true;
                                message = "game over";
                                return;
                        }
                }else{
                       count = 0;
                }
        }

        /* диагональ / */
        count = 0;
	deltaright  = std::min (endX-nx, ny-startY);
	deltaleft = std::min (nx-startX,  endY-ny);
	for (int i = -deltaleft; i <= deltaright; i++){
                if (arr[nx+i][ny-i] == player){
                        ++count;
                        if (count == k){
                                for (int j = 0; j < k; ++j){
                                        arr[nx+i-j][ny-i+j] = player + 2;
                                }
                                ifFinished = true;
                                message = "game over";
                                return;
                        }
                }else{
                       count = 0;
                }
        }

        /*диагональ \ */
        count = 0;
	deltaleft  = std::min (nx-startX, ny-startY);
	deltaright = std::min (endX-nx,   endY-ny);
	for (int i = -deltaleft; i <= deltaright; i++){
                if (arr[nx+i][ny+i] == player){
                        ++count;
                        if (count == k){
                                for (int j = 0; j < k; ++j){
                                        arr[nx+i-j][ny+i-j] = player + 2;
                                }
                                ifFinished = true;
                                message = "game over";
                                return;
                        }
                }else{
                       count = 0;
                }
        }

        return;
}

// обработчик событий от мышки
void CrissCross :: mouseClicked( int x, int y, int player ){
        if (player == 1){
                if (!ifFinished){
                        if ((turn == true) && (arr[(x*n/image->width)][(y*n/(image->height - textArea))] == 0)){
                                arr[(x*n/image->width)][(y*n/(image->height - textArea))] = 1;
                                turn = false;
                                message = "X turn";
                                check(1, (x*n/image->width), (y*n/(image->height - textArea)));
                        } else {
                                if (turn == false){
                                        message = "it's not your turn";
                                } else {
                                        message = "try other square";
                                }
                        }
                }else{
                        message = "game over";
                }
        }

         if (player == 2){
                if (!ifFinished){
                        if ((turn == false)  && (arr[(x*n/image->width)][(y*n/(image->height - textArea))] == 0)){
                                arr[(x*n/image->width)][(y*n/(image->height - textArea))] = 2;
                                turn = true;
                                message = "O turn";
                                check(2, (x*n/image->width), (y*n/(image->height - textArea)));
                        } else {
                                if (turn == true){
                                        message = "it's not your turn";
                                } else {
                                        message = "try other square";
                                }
                        }
               }else{
                        message = "game over";
               }
        }
	show();
}

void myMouseCallback( int event, int x, int y, int flags, void* param ){
        CrissCross* cc = (CrissCross*) param;
        switch( event ){
                case CV_EVENT_MOUSEMOVE: 
                break;

                case CV_EVENT_LBUTTONDOWN:
                        cc->mouseClicked(x, y, 1);
                break;

                 case CV_EVENT_LBUTTONUP:
                 break;

                 case CV_EVENT_RBUTTONDOWN:
                         cc->mouseClicked(x, y, 2);
                 break;

                 case CV_EVENT_RBUTTONUP:
                 break;
        }
}

bool CrissCross:: show(){
        // показываем картинку
        cvCopyImage( image, src );

        for (int i = 0; i < n; ++i){
                for (int j = 0; j < n; ++j){
                        if ((arr[i][j])==1){
                                drawCriss(src, i , j, 10, false);
                        }
                        if ((arr[i][j])==2){
                                drawCross(src, i , j, 10, false);
                        }
                        if ((arr[i][j])==3){
                                 drawCriss(src, i , j, 15, true);
                        }
                        if ((arr[i][j])==4){
                                drawCross(src, i , j, 15, true);
                        }
                }
        }

        // используя шрифт выводим на картинку текст
        cvPutText(src, message, pt, &font, CV_RGB(0, 250, 0) );

        cvShowImage( "CrissCross", src );

        char c = cvWaitKey(33);
        if (c == 27) { // если нажата ESC - выходим
                return false;
        }
        return true;
}

CrissCross :: CrissCross(int size, int areaForText, int num_n, int num_k){
        n = num_n;
        k = num_k;
        image = 0;
        src = 0;
        turn = true;
        textArea = areaForText;
        height = size + textArea;
        width = size;
        ifFinished = false;

        for (int i = 0; i < n; ++i){
                for (int j = 0; j < n; ++j){
                        arr[i][j] = 0;
                }
        }

        // Создаёи 8-битную, 3-канальную картинку
        image = cvCreateImage(cvSize(width, height), 8, 3);

        // заливаем картинку
        cvSet(image, cvScalar(0,0,0));
        for (int i = 1; i < n; ++i){
                cvLine(image, cvPoint(image->width*i/n, 0), cvPoint(image->width*i/n, (image->height - textArea)),CV_RGB(0,0,250),1,8);
                cvLine(image, cvPoint(0, (image->height - textArea)*i/n), cvPoint(image->width, (image->height - textArea)*i/n),CV_RGB(0,0,250),1,8);
        }

        cvLine(image, cvPoint(0, image->height - textArea), cvPoint(image->width, image->height - textArea),CV_RGB(0,250,0),1,8);

        // клонируем картинку 
        src = cvCloneImage(image);

        assert( src != 0 );

        // окно для отображения картинки
        cvNamedWindow("CrissCross",0);

        cvMoveWindow("CrissCross", 0, 0);

        // вешаем обработчик мышки
        cvSetMouseCallback( "CrissCross", myMouseCallback, this);

        // задаём точку для вывода текста
        pt = cvPoint( 40, src->height - 10);
        // инициализация шрифта
        cvInitFont( &font, CV_FONT_HERSHEY_COMPLEX,1.0, 1.0, 0, 1, CV_AA);

        message = "start game";
}

CrissCross:: ~CrissCross(){
        // освобождаем ресурсы
        cvReleaseImage(&image);
        cvReleaseImage(&src);
        // удаляем окно
        cvDestroyWindow("CrissCross");
}
 
